package com.theaf.core.error;

import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.theaf.core.utils.SmExceptionHelper;
import com.theaf.core.web.ResultHandler;
import com.theaf.core.utils.LoginUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * @Author:songwenke
 * @Description:WEB切面操作
 * @Date:create in 10:48 2017/12/1
 * @Modified By:
 **/
@ControllerAdvice
public class ExceptionWarpResultHandler {
	@Autowired
	@Qualifier(ThreadContext.NAME)
	public ThreadContext context;

	@Resource
	private BussinessLogger logger;
	
	@Bean
	public MethodValidationPostProcessor methodValidationPostProcessor() {
		return new MethodValidationPostProcessor();
	}

    /**
     * 方法调用前初始DUBBO的当前用户信息
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        Subject subject = SecurityUtils.getSubject();
        Object ui = subject.getPrincipal();
        if(ui!=null){
            RpcContext.getContext().set(LoginUtils.DUBBO_USER_INFO,ui);
        }
    }

    /**
     * Exception异常处理
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
	public @ResponseBody Object handleUnexpectedServerError(Exception ex) {
        Exception exception = ex;
        if(ex instanceof IncorrectCredentialsException || ex instanceof UnknownAccountException){
            exception = com.theaf.core.utils.SmExceptionHelper.reqAuthFailedException("用户或密码错误!");
        }else if (ex instanceof RpcException) {
            exception = com.theaf.core.utils.SmExceptionHelper.sysCheckException("资源请求失败，接口处理发生错误。");
            logger.error(this, ex.getMessage(), ex);
        } else if (ex instanceof HttpMessageNotReadableException) {
            if (ex.getCause() instanceof InvalidFormatException) {
                InvalidFormatException ife = (InvalidFormatException) ex.getCause();
                exception = com.theaf.core.utils.SmExceptionHelper.reqArgValidException(
                        String.format("访问资源失败，异常请求参数:%s转换%s失败", ife.getPath(), ife.getTargetType()));
            } else {
                exception = com.theaf.core.utils.SmExceptionHelper
                        .reqArgValidException(String.format("访问资源失败，请求参数处理异常：%s", ex.getCause().getMessage()));
            }
        } else if (ex instanceof SmException) {
            logger.error(this, ex.getMessage());
        } else if (ex instanceof MethodArgumentTypeMismatchException) {
            MethodArgumentTypeMismatchException argException = (MethodArgumentTypeMismatchException) ex;
            String message = String.format("访问资源失败，参数值{%s=%s}错误，请检查。", argException.getName(), argException.getValue());
            exception = com.theaf.core.utils.SmExceptionHelper.reqArgValidException(message);
        } else if (ex instanceof MethodArgumentNotValidException) {
            List<ObjectError> errorList = ((MethodArgumentNotValidException) ex).getBindingResult().getAllErrors();
            StringBuilder message = new StringBuilder("请求参数验证失败：");
            if (!CollectionUtils.isEmpty(errorList)) {
                for (ObjectError error : errorList) {
                    message.append(error.getDefaultMessage()).append("；");
                }
            }
            exception = com.theaf.core.utils.SmExceptionHelper.reqArgValidException(message.toString());
        } else if (ex instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> set = ((ConstraintViolationException) ex).getConstraintViolations();
            StringBuilder message = new StringBuilder("请求参数验证失败：");
            for (Iterator<ConstraintViolation<?>> iter = set.iterator(); iter.hasNext(); ) {
                message.append(iter.next().getMessage()).append("；");
            }
            exception = com.theaf.core.utils.SmExceptionHelper.reqArgValidException(message.toString());
        } else if (ex instanceof BindException) {
            BindException bindException = ((BindException) ex);
            BeanPropertyBindingResult bpd = (BeanPropertyBindingResult) bindException.getBindingResult();
            List<FieldError> errors = bpd.getFieldErrors();
            StringBuilder message = new StringBuilder("请求参数异常：");
            for (FieldError error : errors) {
                message.append(error.getField()).append(";");
            }
            exception = SmExceptionHelper.reqArgValidException(message.toString());
        } else {
            logger.error(this, ex.getMessage(), ex);
        }
        // 返回数据
        return ResultHandler.errorWrapper(exception);
    }
}
